package org.richin.support.web.struts;

import org.apache.struts.action.Action;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.action.*;
import org.apache.struts.config.ActionConfig;
import org.apache.struts.util.MessageResources;

public abstract class CommDispatchAction extends Action {
	protected Class clazz;
	protected static Log log;
	protected static MessageResources messages = MessageResources
			.getMessageResources("org.apache.struts.actions.LocalStrings");
	protected HashMap methods;
	protected Class types[];

	static {
		log = LogFactory.getLog(org.apache.struts.actions.DispatchAction.class);
	}
	public CommDispatchAction() {
		clazz = getClass();
		methods = new HashMap();
		types = (new Class[] { org.apache.struts.action.ActionMapping.class, org.apache.struts.action.ActionForm.class,
				javax.servlet.http.HttpServletRequest.class, javax.servlet.http.HttpServletResponse.class });
	}

	public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		if (isCancelled(request)) {
			ActionForward af = cancelled(mapping, form, request, response);
			if (af != null)
				return af;
		}
		String parameter = getParameter(mapping, form, request, response);
		String name = getMethodName(mapping, form, request, response, parameter);
		if ("execute".equals(name) || "perform".equals(name)) {
			String message = messages.getMessage("dispatch.recursive", mapping.getPath());
			log.error(message);
			throw new ServletException(message);
		} else {
			return dispatchMethod(mapping, form, request, response, name);
		}
	}

	protected ActionForward unspecified(ActionMapping mapping, ActionForm form, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		String message = messages.getMessage("dispatch.parameter", mapping.getPath(), mapping.getParameter());
		log.error(message);
		throw new ServletException(message);
	}

	protected ActionForward cancelled(ActionMapping mapping, ActionForm form, HttpServletRequest request,
			HttpServletResponse httpservletresponse) throws Exception {
		return null;
	}

	protected ActionForward dispatchMethod(ActionMapping mapping, ActionForm form, HttpServletRequest request,
			HttpServletResponse response, String name) throws Exception {
		if (name == null)
			return unspecified(mapping, form, request, response);
		Method method = null;
		try {
			method = getMethod(name);
		} catch (NoSuchMethodException e) {
			String message = messages.getMessage("dispatch.method", mapping.getPath(), name);
			log.error(message, e);
			String userMsg = messages.getMessage("dispatch.method.user", mapping.getPath());
			throw new NoSuchMethodException(userMsg);
		}
		ActionForward forward = null;
		try {
			Object args[] = { mapping, form, request, response };
			forward = (ActionForward) method.invoke(this, args);
		} catch (ClassCastException e) {
			String message = messages.getMessage("dispatch.return", mapping.getPath(), name);
			log.error(message, e);
			throw e;
		} catch (IllegalAccessException e) {
			String message = messages.getMessage("dispatch.error", mapping.getPath(), name);
			log.error(message, e);
			throw e;
		} catch (InvocationTargetException e) {
			Throwable t = e.getTargetException();
			if (t instanceof Exception) {
				throw (Exception) t;
			} else {
				String message = messages.getMessage("dispatch.error", mapping.getPath(), name);
				log.error(message, e);
				throw new ServletException(t);
			}
		}
		return forward;
	}

	protected String getParameter(ActionMapping mapping, ActionForm form, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		String parameter = mapping.getParameter();
		if (parameter == null) {
			String message = messages.getMessage("dispatch.handler", mapping.getPath());
			log.error(message);
			throw new ServletException(message);
		} else {
			return parameter;
		}
	}

	protected Method getMethod(String name) throws NoSuchMethodException {
		Method method1;
		synchronized (methods) {
			Method method = (Method) methods.get(name);
			if (method == null) {
				method = clazz.getMethod(name, types);
				methods.put(name, method);
			}
			method1 = method;
		}
		return method1;
	}

	protected String getMethodName(ActionMapping mapping, ActionForm form, HttpServletRequest request,
			HttpServletResponse response, String parameter) throws Exception {
		return request.getParameter(parameter);
	}


}
